home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Pascal Super Library
/
Pascal Super Library (CW International)(1997).bin
/
MATH
/
PIBSIGS
/
ALGAMA.PAS
next >
Wrap
Pascal/Delphi Source File
|
1986-06-22
|
9KB
|
248 lines
(*-------------------------------------------------------------------------*)
(* ALGama -- Logarithm of Gamma Distribution *)
(*-------------------------------------------------------------------------*)
FUNCTION ALGama( Arg : REAL ) : REAL;
(*-------------------------------------------------------------------------*)
(* *)
(* Function: ALGama *)
(* *)
(* Purpose: Calculates Log (base E) of Gamma function *)
(* *)
(* Calling Sequence: *)
(* *)
(* Val := ALGama( Arg ) *)
(* *)
(* Arg --- Gamma distribution parameter (Input) *)
(* Val --- output Log Gamma value *)
(* *)
(* Calls: None *)
(* *)
(* Called By: Many (CDBeta, etc.) *)
(* *)
(* Remarks: *)
(* *)
(* Minimax polynomial approximations are used over the *)
(* intervals [-inf,0], [0,.5], [.5,1.5], [1.5,4.0], *)
(* [4.0,12.0], [12.0,+inf]. *)
(* *)
(* See Hart et al, "Computer Approximations", *)
(* Wiley(1968), p. 130F, and also *)
(* *)
(* Cody and Hillstrom, "Chebyshev approximations for *)
(* the natural logarithm of the Gamma function", *)
(* Mathematics of Computation, 21, April, 1967, P. 198F. *)
(* *)
(* *)
(* There are some machine-dependent constants used -- *)
(* *)
(* Rmax --- Largest value for which ALGama *)
(* can be safely computed. *)
(* Rinf --- Largest floating-point number. *)
(* Zeta --- Smallest floating-point number *)
(* such that (1 + Zeta) = 1. *)
(* *)
(*-------------------------------------------------------------------------*)
VAR
Rarg : REAL;
Alinc : REAL;
Scale : REAL;
Top : REAL;
Bot : REAL;
Frac : REAL;
Algval : REAL;
I : INTEGER;
Iapprox : INTEGER;
Iof : INTEGER;
Ilo : INTEGER;
Ihi : INTEGER;
Qminus : BOOLEAN;
Qdoit : BOOLEAN;
(* Structured *) CONST
P : ARRAY [ 1 .. 29 ] OF REAL =
( 4.12084318584770E+00 ,
8.56898206283132E+01 ,
2.43175243524421E+02 ,
-2.61721858385614E+02 ,
-9.22261372880152E+02 ,
-5.17638349802321E+02 ,
-7.74106407133295E+01 ,
-2.20884399721618E+00 ,
5.15505761764082E+00 ,
3.77510679797217E+02 ,
5.26898325591498E+03 ,
1.95536055406304E+04 ,
1.20431738098716E+04 ,
-2.06482942053253E+04 ,
-1.50863022876672E+04 ,
-1.51383183411507E+03 ,
-1.03770165173298E+04 ,
-9.82710228142049E+05 ,
-1.97183011586092E+07 ,
-8.73167543823839E+07 ,
1.11938535429986E+08 ,
4.81807710277363E+08 ,
-2.44832176903288E+08 ,
-2.40798698017337E+08 ,
8.06588089900001E-04 ,
-5.94997310888900E-04 ,
7.93650067542790E-04 ,
-2.77777777688189E-03 ,
8.33333333333330E-02 );
Q : ARRAY [ 1 .. 24 ] OF REAL =
( 1.00000000000000E+00 ,
4.56467718758591E+01 ,
3.77837248482394E+02 ,
9.51323597679706E+02 ,
8.46075536202078E+02 ,
2.62308347026946E+02 ,
2.44351966250631E+01 ,
4.09779292109262E-01 ,
1.00000000000000E+00 ,
1.28909318901296E+02 ,
3.03990304143943E+03 ,
2.20295621441566E+04 ,
5.71202553960250E+04 ,
5.26228638384119E+04 ,
1.44020903717009E+04 ,
6.98327414057351E+02 ,
1.00000000000000E+00 ,
-2.01527519550048E+03 ,
-3.11406284734067E+05 ,
-1.04857758304994E+07 ,
-1.11925411626332E+08 ,
-4.04435928291436E+08 ,
-4.35370714804374E+08 ,
-7.90261111418763E+07 );
BEGIN (* ALGama *)
(* Initialize *)
Algval := Rinf;
Scale := 1.0;
Alinc := 0.0;
Frac := 0.0;
Rarg := Arg;
Iof := 1;
Qminus := FALSE;
Qdoit := TRUE;
(* Adjust for negative argument *)
IF( Rarg < 0.0 ) THEN
BEGIN
Qminus := TRUE;
Rarg := -Rarg;
Top := Int( Rarg );
Bot := 1.0;
IF( ( INT( Top / 2.0 ) * 2.0 ) = 0.0 ) THEN Bot := -1.0;
Top := Rarg - Top;
IF( Top = 0.0 ) THEN
Qdoit := FALSE
ELSE
BEGIN
Frac := Bot * PI / SIN( Top * PI );
Rarg := Rarg + 1.0;
Frac := LN( ABS( Frac ) );
END;
END;
(* Choose approximation interval *)
(* based upon argument range *)
IF( Rarg = 0.0 ) THEN
Qdoit := FALSE
ELSE IF( Rarg <= 0.5 ) THEN
BEGIN
Alinc := -LN( Rarg );
Scale := Rarg;
Rarg := Rarg + 1.0;
IF( Scale < Zeta ) THEN
BEGIN
Algval := Alinc;
Qdoit := FALSE;
END;
END
ELSE IF ( Rarg <= 1.5 ) THEN
Scale := Rarg - 1.0
ELSE IF( Rarg <= 4.0 ) THEN
BEGIN
Scale := Rarg - 2.0;
Iof := 9;
END
ELSE IF( Rarg <= 12.0 ) THEN
Iof := 17
ELSE IF( Rarg <= RMAX ) THEN
BEGIN
Alinc := ( Rarg - 0.5 ) * LN( Rarg ) - Rarg + Xln2sp;
Scale := 1.0 / Rarg;
Rarg := Scale * Scale;
Top := P[ 25 ];
FOR I := 26 TO 29 DO
Top := Top * Rarg + P[ I ];
Algval := Scale * Top + Alinc;
Qdoit := FALSE;
END;
(* Common evaluation code for Arg <= 12. *)
(* Horner's method is used, which seems *)
(* to give better accuracy than *)
(* continued fractions. *)
IF Qdoit THEN
BEGIN
Ilo := Iof + 1;
Ihi := Iof + 7;
Top := P[ Iof ];
Bot := Q[ Iof ];
FOR I := Ilo TO Ihi DO
BEGIN
Top := Top * Rarg + P[ I ];
Bot := Bot * Rarg + Q[ I ];
END;
Algval := Scale * ( Top / Bot ) + Alinc;
END;
IF( Qminus ) THEN Algval := Frac - Algval;
ALGama := Algval;
END (* ALGama *);